//-----------------------------------------------------------------------
// <copyright file="MethodParameterElement.cs" company="iron9light">
//      Copyright (c) iron9light. All rights reserved.
// </copyright>
// <author>iron9light</author>
//-----------------------------------------------------------------------

namespace EventBrokerExtension.Configuration
{
    using System;
    using System.Configuration;
    using System.Globalization;
    using System.Xml;

    using Microsoft.Practices.Unity.Configuration;

    using Properties;

    /// <summary>
    /// Configuration element for storing the values of method parameters.
    /// </summary>
    public class MethodParameterElement : TypeResolvingConfigurationElement
    {
        /// <summary>
        /// Gets or sets the name of this parameter.
        /// Doesn't have to match the actual parameter name
        /// in the method or constructor, it's just required for uniqueness.
        /// </summary>
        [ConfigurationProperty("name", IsRequired = true)]
        public string Name
        {
            get { return (string)this["name"]; }
            set { this["name"] = value; }
        }

        /// <summary>
        /// Gets or sets the type of this parameter.
        /// </summary>
        [ConfigurationProperty("parameterType", IsRequired = false)]
        public string ParameterTypeName
        {
            get { return (string)this["parameterType"]; }
            set { this["parameterType"] = value; }
        }

        /// <summary>
        /// Gets or sets the generic parameter name of this parameter.
        /// </summary>
        [ConfigurationProperty("genericParameterName", IsRequired = false)]
        public string GenericParameterName
        {
            get { return (string)this["genericParameterName"]; }
            set { this["genericParameterName"] = value; }
        }

        /// <summary>
        /// Get the <see cref="MethodParameter"/> object for this parameter
        /// to feed to the container configuration API.
        /// </summary>
        /// <returns>The created <see cref="MethodParameter"/> object.</returns>
        public MethodParameter CreateInjectionParameterValue()
        {
            if (!string.IsNullOrEmpty(this.GenericParameterName))
            {
                return new GenericParameter(this.GenericParameterName);
            }

            Type type = this.TypeResolver.ResolveType(this.ParameterTypeName);
            return new TypedParameter(type);
        }

        /// <summary>
        /// Reads XML from the configuration file.
        /// </summary>
        /// <param name="reader">The <see cref="XmlReader"/> that reads from the configuration file.</param>
        /// <param name="serializeCollectionKey"><see langword="true"/> to serialize only the collectionkey properties; 
        /// otherwise, <see langword="false"/>.</param>
        protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
        {
            GuardAttributeOccurrences(reader);

            base.DeserializeElement(reader, serializeCollectionKey);
        }

        private static void GuardAttributeOccurrences(XmlReader reader)
        {
            int attributeCount = GetAttributeCount(reader, "parameterType")
                                 + GetAttributeCount(reader, "genericParameterName");

            if (attributeCount > 1)
            {
                throw new ConfigurationErrorsException(
                        string.Format(
                                CultureInfo.CurrentCulture,
                                Resources.OnlyOneOfParameterTypeAndGenericParameterNameAllowed,
                                reader.GetAttribute("name")),
                        reader);
            }

            if (attributeCount == 0)
            {
                throw new ConfigurationErrorsException(
                        string.Format(
                                CultureInfo.CurrentCulture,
                                Resources.NeitherParameterTypeNorGenericParameterNameSpecified,
                                reader.GetAttribute("name")),
                        reader);
            }
        }

        private static int GetAttributeCount(XmlReader reader, string attributeName)
        {
            return string.IsNullOrEmpty(reader.GetAttribute(attributeName)) ? 0 : 1;
        }
    }
}